using System;
using FwkLight.CodeExtensions;
using FwkLight.Domain;
using FwkLight.Domain.Fetching;
using FwkLight.Domain.Repository;
using FwkLight.Persistence;

namespace FwkLight.Application
{
  public abstract class CurrentEntityTask<EntityType> : CurrentEntityTask<EntityType, int>
  {
    protected CurrentEntityTask(IBaseRepo<EntityType> repository, INHUnitOfWorkProvider uowProvider) : base(repository, uowProvider)
    {
    }
  }

	[KeepEntityForCurrentRequest]
	public abstract class CurrentEntityTask<EntityType, MainRetrievalType> : BaseLoadTask<EntityType>
	{
	  private MainRetrievalType _currentIdentifier;

	  protected CurrentEntityTask(IBaseRepo<EntityType> repository, INHUnitOfWorkProvider uowProvider) : base(repository, uowProvider)
	  {
	  }

	  public EntityType Execute()
		{
			ExecuteInternal();
			return Entity;
		}

		protected override void  LoadDataNeccesaryForLoadEntityDecisions()
		{
			if (Entity != null)
				return;

			_currentIdentifier = ObtainCurrentId();
		}

    protected override void ConfigureFilters()
    {
      if (CurrentIdentifierCanBeUsed())
        new WaitForFilter<EntityType, MainRetrievalType>(DomainConstants.IdPartialName, Fetcher, Fetcher.InitFetchingHierarchy()).Eq(_currentIdentifier);
    }
 
    private bool CurrentIdentifierCanBeUsed()
    {
      return ((typeof (MainRetrievalType) != typeof (string) && _currentIdentifier != null)
              || (typeof (MainRetrievalType) == typeof (string) && _currentIdentifier.ToString().IsNotEmpty()));
    }

    protected override void LoadEntity()
    {
      if (CurrentIdentifierCanBeUsed())
        base.LoadEntity();
      else
        LoadEntityWhenCurrentIdentifierDoesNotHaveValue();
    }

		protected virtual void LoadEntityWhenCurrentIdentifierDoesNotHaveValue()
		{
			
		}

		protected abstract MainRetrievalType ObtainCurrentId();

		public void SetCurrentEntity(EntityType entity)
		{
			Entity = entity;
		}
	}
}